import pygame
import os
from config import Config
from game import GameLogic
from utils import draw_text, render_text

class Button:
    """可点击的按钮"""
    def __init__(self, x, y, width, height, text, callback):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.callback = callback
        self.hovered = False
        self.active = True
        self.font = None
        self.animation_progress = 0  # 动画进度
        self.animation_speed = 0.2  # 动画速度
    
    def draw(self, surface):
        """绘制按钮"""
        # 计算动画过渡
        if self.hovered:
            self.animation_progress = min(1.0, self.animation_progress + self.animation_speed)
        else:
            self.animation_progress = max(0.0, self.animation_progress - self.animation_speed)
        
        # 计算当前颜色
        base_color = Config.BUTTON_COLOR
        hover_color = Config.BUTTON_HOVER_COLOR
        current_color = tuple(
            int(base + (hover - base) * self.animation_progress)
            for base, hover in zip(base_color, hover_color)
        )
        
        # 绘制按钮背景
        pygame.draw.rect(surface, current_color, self.rect, border_radius=8)
        
        # 绘制按钮边框
        border_color = tuple(
            min(255, int(c * (1 + 0.2 * self.animation_progress)))
            for c in Config.TEXT_COLOR
        )
        pygame.draw.rect(surface, border_color, self.rect, 2, border_radius=8)
        
        # 绘制按钮文本
        text_color = tuple(
            min(255, int(c * (1 + 0.2 * self.animation_progress)))
            for c in Config.TEXT_COLOR
        )
        draw_text(surface, self.text, self.rect.center, Config.FONT_SIZE, 
                 text_color, center=True, bold=self.animation_progress > 0.5)
    
    def handle_event(self, event):
        """处理事件"""
        if not self.active:
            return False
            
        if event.type == pygame.MOUSEMOTION:
            self.hovered = self.rect.collidepoint(event.pos)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1 and self.rect.collidepoint(event.pos):
                self.callback()
                return True
        return False

class Slider:
    """滑动条控件"""
    def __init__(self, x, y, width, height, min_value, max_value, 
                 initial_value, callback):
        self.rect = pygame.Rect(x, y, width, height)
        self.min_value = min_value
        self.max_value = max_value
        self.value = initial_value
        self.callback = callback
        self.dragging = False
        self.font = None
        
        # 滑块的矩形
        self.handle_width = 10
        self.handle_rect = pygame.Rect(0, 0, self.handle_width, height)
        self.update_handle_position()
    
    def update_handle_position(self):
        """更新滑块位置"""
        value_range = self.max_value - self.min_value
        if value_range == 0:
            position = 0
        else:
            position = (self.value - self.min_value) / value_range
        
        handle_x = self.rect.x + int(position * (self.rect.width - self.handle_width))
        self.handle_rect.x = handle_x
        self.handle_rect.y = self.rect.y
    
    def set_value_from_position(self, x):
        """根据鼠标位置设置值"""
        position = (x - self.rect.x) / self.rect.width
        position = max(0, min(1, position))
        new_value = self.min_value + position * (self.max_value - self.min_value)
        new_value = int(new_value)
        
        # 只在值发生变化时更新
        if new_value != self.value:
            self.value = new_value
            self.update_handle_position()
            self.callback(self.value)
    
    def draw(self, surface):
        """绘制滑动条"""
        # 绘制滑动条背景
        pygame.draw.rect(surface, Config.BUTTON_COLOR, self.rect)
        pygame.draw.rect(surface, Config.TEXT_COLOR, self.rect, 1)
        
        # 绘制滑块
        pygame.draw.rect(surface, Config.BUTTON_HOVER_COLOR, self.handle_rect)
        pygame.draw.rect(surface, Config.TEXT_COLOR, self.handle_rect, 1)
        
        # 绘制当前值
        value_pos = (self.rect.right + 30, self.rect.centery)
        draw_text(surface, str(self.value), value_pos, Config.FONT_SIZE, 
                 Config.TEXT_COLOR)
    
    def handle_event(self, event):
        """处理事件"""
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1 and self.handle_rect.collidepoint(event.pos):
                self.dragging = True
                return True
            elif event.button == 1 and self.rect.collidepoint(event.pos):
                self.set_value_from_position(event.pos[0])
                self.dragging = True
                return True
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1 and self.dragging:
                self.dragging = False
                return True
        elif event.type == pygame.MOUSEMOTION:
            if self.dragging:
                self.set_value_from_position(event.pos[0])
                return True
        return False

class GridView:
    """网格视图"""
    def __init__(self, game_logic, rect):
        self.game_logic = game_logic
        self.rect = rect
        self.offset_x = 0
        self.offset_y = 0
        self.scale = 1.0
        self.dragging = False
        self.drag_start = None
        self.last_cell = None
        self.drawing = False
        self.erasing = False
    
    def draw(self, surface):
        """绘制网格"""
        # 填充背景
        pygame.draw.rect(surface, Config.BACKGROUND_COLOR, self.rect)
        
        # 计算可见的网格范围
        cell_size = Config.CELL_SIZE * self.scale
        visible_width = self.rect.width / cell_size
        visible_height = self.rect.height / cell_size
        
        start_x = max(0, int(-self.offset_x / cell_size))
        start_y = max(0, int(-self.offset_y / cell_size))
        end_x = min(self.game_logic.width, int((-self.offset_x + self.rect.width) / cell_size) + 1)
        end_y = min(self.game_logic.height, int((-self.offset_y + self.rect.height) / cell_size) + 1)
        
        # 绘制网格线
        for x in range(start_x, end_x + 1):
            screen_x = self.grid_to_screen_x(x)
            pygame.draw.line(surface, Config.GRID_COLOR, 
                            (screen_x, self.rect.top), 
                            (screen_x, self.rect.bottom))
        
        for y in range(start_y, end_y + 1):
            screen_y = self.grid_to_screen_y(y)
            pygame.draw.line(surface, Config.GRID_COLOR, 
                            (self.rect.left, screen_y), 
                            (self.rect.right, screen_y))
        
        # 绘制活细胞
        for y in range(start_y, end_y):
            for x in range(start_x, end_x):
                if self.game_logic.grid[y][x].alive:
                    screen_x = self.grid_to_screen_x(x)
                    screen_y = self.grid_to_screen_y(y)
                    cell_rect = pygame.Rect(
                        screen_x + 1, screen_y + 1,  # 留出1像素的边距
                        cell_size - 2, cell_size - 2  # 减小2像素以保留网格线
                    )
                    pygame.draw.rect(surface, Config.CELL_COLOR, cell_rect)
        
        # 绘制边框
        pygame.draw.rect(surface, Config.TEXT_COLOR, self.rect, 1)
    
    def grid_to_screen_x(self, x):
        """网格X坐标转屏幕坐标"""
        return self.rect.left + (x * Config.CELL_SIZE * self.scale) + self.offset_x
    
    def grid_to_screen_y(self, y):
        """网格Y坐标转屏幕坐标"""
        return self.rect.top + (y * Config.CELL_SIZE * self.scale) + self.offset_y
    
    def screen_to_grid(self, screen_x, screen_y):
        """屏幕坐标转网格坐标"""
        grid_x = int((screen_x - self.rect.left - self.offset_x) / (Config.CELL_SIZE * self.scale))
        grid_y = int((screen_y - self.rect.top - self.offset_y) / (Config.CELL_SIZE * self.scale))
        return grid_x, grid_y
    
    def handle_event(self, event):
        """处理事件"""
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.rect.collidepoint(event.pos):
                if event.button == 1:  # 左键
                    grid_x, grid_y = self.screen_to_grid(event.pos[0], event.pos[1])
                    if 0 <= grid_x < self.game_logic.width and 0 <= grid_y < self.game_logic.height:
                        self.drawing = not self.game_logic.grid[grid_y][grid_x].alive
                        self.erasing = not self.drawing
                        self.game_logic.toggle_cell(grid_x, grid_y)
                        self.last_cell = (grid_x, grid_y)
                    return True
                elif event.button == 2:  # 中键
                    self.dragging = True
                    self.drag_start = event.pos
                    return True
                elif event.button == 4:  # 滚轮上
                    self.zoom(1.1, event.pos)
                    return True
                elif event.button == 5:  # 滚轮下
                    self.zoom(0.9, event.pos)
                    return True
        
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                self.drawing = False
                self.erasing = False
                self.last_cell = None
                return True
            elif event.button == 2:
                self.dragging = False
                self.drag_start = None
                return True
        
        elif event.type == pygame.MOUSEMOTION:
            if self.dragging and self.drag_start:
                dx = event.pos[0] - self.drag_start[0]
                dy = event.pos[1] - self.drag_start[1]
                self.offset_x += dx
                self.offset_y += dy
                self.drag_start = event.pos
                return True
            
            if (self.drawing or self.erasing) and self.rect.collidepoint(event.pos):
                grid_x, grid_y = self.screen_to_grid(event.pos[0], event.pos[1])
                if (0 <= grid_x < self.game_logic.width and 
                    0 <= grid_y < self.game_logic.height and 
                    (grid_x, grid_y) != self.last_cell):
                    cell = self.game_logic.grid[grid_y][grid_x]
                    if (self.drawing and not cell.alive) or (self.erasing and cell.alive):
                        self.game_logic.toggle_cell(grid_x, grid_y)
                        self.last_cell = (grid_x, grid_y)
                    return True
        
        return False
    
    def zoom(self, factor, center):
        """缩放网格"""
        old_scale = self.scale
        self.scale *= factor
        self.scale = max(0.1, min(5.0, self.scale))
        
        # 调整偏移量，使缩放以鼠标位置为中心
        if self.scale != old_scale:
            zoom_center_x = center[0] - self.rect.left
            zoom_center_y = center[1] - self.rect.top
            
            self.offset_x = zoom_center_x - (zoom_center_x - self.offset_x) * (self.scale / old_scale)
            self.offset_y = zoom_center_y - (zoom_center_y - self.offset_y) * (self.scale / old_scale)

class Dropdown:
    """下拉菜单控件"""
    def __init__(self, x, y, width, height, items, callback):
        self.rect = pygame.Rect(x, y, width, height)
        self.items = items
        self.callback = callback
        self.expanded = False
        self.selected_index = 0
        self.hovered_index = -1
        self.item_height = height
        self.max_visible_items = 5  # 最大可见选项数
    
    def draw(self, surface):
        """绘制下拉菜单"""
        # 绘制主按钮
        pygame.draw.rect(surface, Config.BUTTON_COLOR, self.rect, border_radius=8)
        pygame.draw.rect(surface, Config.TEXT_COLOR, self.rect, 2, border_radius=8)
        
        # 绘制当前选中的文本
        if self.items:
            draw_text(surface, self.items[self.selected_index], 
                     (self.rect.x + 10, self.rect.centery), 
                     Config.FONT_SIZE, Config.TEXT_COLOR)
        
        # 绘制展开箭头
        arrow_points = [
            (self.rect.right - 20, self.rect.centery - 5),
            (self.rect.right - 15, self.rect.centery + 5),
            (self.rect.right - 25, self.rect.centery + 5)
        ]
        pygame.draw.polygon(surface, Config.TEXT_COLOR, arrow_points)
        
        # 如果展开，绘制选项列表
        if self.expanded:
            # 计算可见的选项范围
            start_index = max(0, min(self.selected_index - self.max_visible_items // 2,
                                   len(self.items) - self.max_visible_items))
            end_index = min(start_index + self.max_visible_items, len(self.items))
            
            # 创建选项列表的裁剪区域
            list_height = (end_index - start_index) * self.item_height
            list_rect = pygame.Rect(
                self.rect.x,
                self.rect.bottom,
                self.rect.width,
                list_height
            )
            
            # 绘制选项列表背景
            pygame.draw.rect(surface, Config.BACKGROUND_COLOR, list_rect)
            pygame.draw.rect(surface, Config.TEXT_COLOR, list_rect, 1)
            
            # 绘制可见的选项
            for i in range(start_index, end_index):
                item_rect = pygame.Rect(
                    self.rect.x,
                    self.rect.bottom + (i - start_index) * self.item_height,
                    self.rect.width,
                    self.item_height
                )
                
                # 绘制选项背景
                if i == self.hovered_index:
                    pygame.draw.rect(surface, Config.BUTTON_HOVER_COLOR, item_rect)
                else:
                    pygame.draw.rect(surface, Config.BUTTON_COLOR, item_rect)
                
                # 绘制选项文本
                draw_text(surface, self.items[i], 
                         (item_rect.x + 10, item_rect.centery),
                         Config.FONT_SIZE, Config.TEXT_COLOR)
    
    def handle_event(self, event):
        """处理事件"""
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:  # 左键点击
                if self.rect.collidepoint(event.pos):
                    self.expanded = not self.expanded
                    return True
                
                if self.expanded:
                    # 计算可见的选项范围
                    start_index = max(0, min(self.selected_index - self.max_visible_items // 2,
                                           len(self.items) - self.max_visible_items))
                    end_index = min(start_index + self.max_visible_items, len(self.items))
                    
                    # 检查是否点击了选项
                    for i in range(start_index, end_index):
                        item_rect = pygame.Rect(
                            self.rect.x,
                            self.rect.bottom + (i - start_index) * self.item_height,
                            self.rect.width,
                            self.item_height
                        )
                        if item_rect.collidepoint(event.pos):
                            self.selected_index = i
                            self.expanded = False
                            self.callback(self.items[i])
                            return True
                    
                    # 如果点击了其他地方，关闭下拉菜单
                    self.expanded = False
                    return True
        
        elif event.type == pygame.MOUSEMOTION:
            if self.expanded:
                # 计算可见的选项范围
                start_index = max(0, min(self.selected_index - self.max_visible_items // 2,
                                       len(self.items) - self.max_visible_items))
                end_index = min(start_index + self.max_visible_items, len(self.items))
                
                # 更新悬停状态
                for i in range(start_index, end_index):
                    item_rect = pygame.Rect(
                        self.rect.x,
                        self.rect.bottom + (i - start_index) * self.item_height,
                        self.rect.width,
                        self.item_height
                    )
                    if item_rect.collidepoint(event.pos):
                        self.hovered_index = i
                        return True
                self.hovered_index = -1
        
        return False

class ControlPanel:
    """控制面板"""
    def __init__(self, game_logic, rect):
        self.game_logic = game_logic
        self.rect = rect
        self.buttons = []
        self.speed_slider = None
        self.grid_size_slider = None
        self.pattern_dropdown = None
        self.font = None
        self.setup_controls()
    
    def setup_controls(self):
        """设置控制按钮"""
        button_width = Config.BUTTON_WIDTH
        button_height = Config.BUTTON_HEIGHT
        margin = Config.BUTTON_MARGIN
        
        # 计算按钮位置
        start_x = self.rect.left + margin
        y = self.rect.top + 50  # 标题下方留出空间
        
        # 按钮文本列表 - 调整顺序，让开始和暂停按钮并排
        button_texts = [
            # 第一行：开始和暂停
            (Config.BTN_START, self.on_start_click),
            (Config.BTN_PAUSE, self.on_pause_click),
            # 第二行：单步和清除
            (Config.BTN_STEP, self.on_step_click),
            (Config.BTN_CLEAR, self.on_clear_click),
            # 第三行：随机和保存
            (Config.BTN_RANDOM, self.on_random_click),
            (Config.BTN_SAVE, self.on_save_click),
            # 第四行：加载
            (Config.BTN_LOAD, self.on_load_click)
        ]
        
        # 计算每列的按钮数量
        buttons_per_column = 2  # 固定为2列
        
        # 添加按钮
        for i, (text, callback) in enumerate(button_texts):
            # 确定按钮所在的列
            column = i % buttons_per_column
            row = i // buttons_per_column
            
            # 计算按钮位置
            x = start_x + column * (button_width + margin)
            button_y = y + row * (button_height + margin)
            
            # 创建按钮并设置样式
            button = Button(
                x, button_y, button_width, button_height,
                text, callback
            )
            self.buttons.append(button)
        
        # 计算滑动条位置
        slider_y = y + (len(button_texts) // 2 + 1) * (button_height + margin)
        slider_width = button_width * 2 + margin
        
        # 添加速度滑动条
        self.speed_slider = Slider(
            start_x, slider_y, slider_width, Config.SLIDER_HEIGHT,
            Config.MIN_SPEED, Config.MAX_SPEED, Config.DEFAULT_SPEED,
            self.on_speed_change
        )
        
        # 添加网格大小滑动条
        grid_size_y = slider_y + Config.SLIDER_HEIGHT + margin
        self.grid_size_slider = Slider(
            start_x, grid_size_y, slider_width, Config.SLIDER_HEIGHT,
            Config.MIN_GRID_SIZE, Config.MAX_GRID_SIZE, Config.DEFAULT_GRID_SIZE,
            self.on_grid_size_change
        )
        
        # 添加图案下拉菜单
        dropdown_y = grid_size_y + Config.SLIDER_HEIGHT + margin
        self.pattern_dropdown = Dropdown(
            start_x, dropdown_y, slider_width, Config.DROPDOWN_HEIGHT,
            list(Config.PATTERNS.keys()), self.on_pattern_select
        )
    
    def draw(self, surface):
        """绘制控制面板"""
        # 填充背景
        pygame.draw.rect(surface, Config.BACKGROUND_COLOR, self.rect)
        
        # 绘制标题
        title_pos = (self.rect.centerx, self.rect.top + 20)
        draw_text(surface, "控制面板", title_pos, Config.TITLE_FONT_SIZE, 
                 Config.TEXT_COLOR, center=True, bold=True)
        
        # 绘制按钮
        for button in self.buttons:
            button.draw(surface)
        
        # 绘制滑动条
        if self.speed_slider:
            self.speed_slider.draw(surface)
            label_pos = (self.speed_slider.rect.left, self.speed_slider.rect.top - 5)
            draw_text(surface, "速度:", label_pos, Config.FONT_SIZE, 
                     Config.TEXT_COLOR, center=False)
        
        # 绘制网格大小滑动条
        if self.grid_size_slider:
            self.grid_size_slider.draw(surface)
            label_pos = (self.grid_size_slider.rect.left, self.grid_size_slider.rect.top - 5)
            size_text = Config.TEXT_GRID_SIZE.format(
                self.grid_size_slider.value,
                self.grid_size_slider.value
            )
            draw_text(surface, size_text, label_pos, Config.FONT_SIZE,
                     Config.TEXT_COLOR, center=False)
        
        # 绘制图案下拉菜单
        if self.pattern_dropdown:
            self.pattern_dropdown.draw(surface)
            label_pos = (self.pattern_dropdown.rect.left, self.pattern_dropdown.rect.top - 5)
            draw_text(surface, "预设图案:", label_pos, Config.FONT_SIZE,
                     Config.TEXT_COLOR, center=False)
        
        # 绘制边框
        pygame.draw.rect(surface, Config.TEXT_COLOR, self.rect, 1)
    
    def handle_event(self, event):
        """处理事件"""
        # 处理按钮事件
        for button in self.buttons:
            if button.handle_event(event):
                return True
        
        # 处理滑动条事件
        if self.speed_slider and self.speed_slider.handle_event(event):
            return True
        
        if self.grid_size_slider and self.grid_size_slider.handle_event(event):
            return True
        
        # 处理下拉菜单事件
        if self.pattern_dropdown and self.pattern_dropdown.handle_event(event):
            return True
            
        return False
    
    def update(self):
        """更新控制面板状态"""
        # 更新开始/暂停按钮文本
        start_button = self.buttons[0]
        pause_button = self.buttons[1]
        
        if self.game_logic.running:
            start_button.text = "停止"
            pause_button.active = True
        else:
            start_button.text = "开始"
            pause_button.active = False
        
        if self.game_logic.paused:
            pause_button.text = "继续"
        else:
            pause_button.text = "暂停"
    
    # 按钮回调函数
    def on_start_click(self):
        """开始/停止按钮回调"""
        if self.game_logic.running:
            self.game_logic.stop()
        else:
            self.game_logic.start()
    
    def on_pause_click(self):
        """暂停/继续按钮回调"""
        self.game_logic.pause()
    
    def on_step_click(self):
        """单步按钮回调"""
        self.game_logic.step()
    
    def on_clear_click(self):
        """清除按钮回调"""
        self.game_logic.clear()
    
    def on_random_click(self):
        """随机按钮回调"""
        self.game_logic.randomize()
    
    def on_grid_size_change(self, value):
        """处理网格大小改变"""
        self.game_logic.resize_grid(value, value)
    
    def on_pattern_select(self, pattern_name):
        """处理图案选择"""
        if pattern_name in Config.PATTERNS:
            pattern = Config.PATTERNS[pattern_name]
            self.game_logic.load_pattern(pattern)
    
    def on_save_click(self):
        """保存当前状态"""
        import tkinter as tk
        from tkinter import filedialog
        
        root = tk.Tk()
        root.withdraw()  # 隐藏主窗口
        
        file_path = filedialog.asksaveasfilename(
            defaultextension=".json",
            filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
            title="保存游戏状态"
        )
        
        if file_path:
            self.game_logic.save_state(file_path)
    
    def on_load_click(self):
        """加载保存的状态"""
        import tkinter as tk
        from tkinter import filedialog
        
        root = tk.Tk()
        root.withdraw()  # 隐藏主窗口
        
        file_path = filedialog.askopenfilename(
            filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
            title="加载游戏状态"
        )
        
        if file_path:
            try:
                self.game_logic.load_state(file_path)
            except Exception as e:
                print(f"加载失败: {e}")
    
    def on_speed_change(self, value):
        # 速度改变回调，在main.py中使用
        pass

class DataDisplay:
    """数据显示面板"""
    def __init__(self, game_logic, rect):
        self.game_logic = game_logic
        self.rect = rect
        self.font = None
    
    def draw(self, surface):
        """绘制数据显示面板"""
        # 填充背景
        pygame.draw.rect(surface, Config.BACKGROUND_COLOR, self.rect)
        
        # 绘制标题
        title_pos = (self.rect.centerx, self.rect.top + 20)
        draw_text(surface, "数据显示", title_pos, Config.TITLE_FONT_SIZE, 
                 Config.TEXT_COLOR, center=True, bold=True)
        
        # 绘制数据
        y = self.rect.top + 50
        line_height = 25
        
        # 代数
        generation_text = Config.TEXT_GENERATION.format(self.game_logic.generation)
        self.draw_text(surface, generation_text, y)
        y += line_height
        
        # 活细胞数量
        alive_text = Config.TEXT_ALIVE_CELLS.format(self.game_logic.get_alive_count())
        self.draw_text(surface, alive_text, y)
        y += line_height
        
        # 状态
        status = "运行中"
        if not self.game_logic.running:
            status = "停止"
        elif self.game_logic.paused:
            status = "暂停"
        status_text = Config.TEXT_STATUS.format(status)
        self.draw_text(surface, status_text, y)
        
        # 绘制边框
        pygame.draw.rect(surface, Config.TEXT_COLOR, self.rect, 1)
    
    def draw_text(self, surface, text, y):
        """在指定位置绘制文本"""
        pos = (self.rect.left + 20, y)
        draw_text(surface, text, pos, Config.FONT_SIZE, Config.TEXT_COLOR)
    
    def update(self):
        """更新数据"""
        # 数据直接从game_logic获取，不需要额外更新
        pass